import { Node, mergeAttributes } from "@tiptap/core";
import { Plugin, PluginKey } from "@tiptap/pm/state";
import { VueNodeViewRenderer } from "@tiptap/vue-3";
// @ts-ignore - Vue 文件类型声明
import TocNodeView from "./node-view.vue";

export interface TocOptions {
  HTMLAttributes: Record<string, any>;
}

declare module "@tiptap/core" {
  interface Commands<ReturnType> {
    toc: {
      /**
       * 插入目录
       */
      addTableOfContents: (options?: any) => ReturnType;
      /**
       * 更新目录
       */
      updateTableOfContents: () => ReturnType;
    };
  }

  interface Storage {
    tableOfContents: {
      content: Array<{
        id: string;
        textContent: string;
        level: number;
        originalLevel: number;
      }>;
    };
  }
}

/**
 * TOC (Table of Contents) 扩展
 * 用于在文档中插入目录
 */
export const Toc = Node.create<TocOptions>({
  name: "toc",

  group: "block",

  // 原子节点，不可编辑内部内容
  atom: true,

  addOptions() {
    return {
      HTMLAttributes: {},
    };
  },

  addAttributes() {
    return {
      id: {
        default: null,
        parseHTML: (element) => element.getAttribute("data-toc-id"),
        renderHTML: (attributes) => {
          if (!attributes.id) {
            return {};
          }
          return {
            "data-toc-id": attributes.id,
          };
        },
      },
    };
  },

  parseHTML() {
    return [{ tag: 'div[data-type="toc"]' }];
  },

  renderHTML({ HTMLAttributes }) {
    return ["div", mergeAttributes(HTMLAttributes, { "data-type": "toc" })];
  },

  addNodeView() {
    return VueNodeViewRenderer(TocNodeView);
  },

  addCommands() {
    // 扫描文档中的标题节点的辅助函数
    const scanHeadings = (doc: any) => {
      const headings: Array<{
        id: string;
        textContent: string;
        level: number;
        originalLevel: number;
      }> = [];

      doc.descendants((node: any, pos: number) => {
        if (node.type.name === "heading") {
          const level = node.attrs.level as number;
          const textContent = node.textContent.trim();

          if (textContent) {
            // 生成唯一 ID（基于位置和内容）
            const id = `heading-${pos}-${level}-${textContent
              .slice(0, 10)
              .replace(/\s/g, "")}`;

            headings.push({
              id,
              textContent,
              level,
              originalLevel: level,
            });
          }
        }
      });

      return headings;
    };

    return {
      addTableOfContents:
        (options = {}) =>
        ({ chain }) => {
          const id = options.id || `toc-${Date.now()}`;
          return chain()
            .insertContent({
              type: this.name,
              attrs: { id },
            })
            .run();
        },
      updateTableOfContents:
        () =>
        ({ state }) => {
          // 确保 storage 存在
          if (!this.editor.storage.tableOfContents) {
            this.editor.storage.tableOfContents = {
              content: [],
            };
          }

          // 手动扫描文档并更新 storage
          const headings = scanHeadings(state.doc);
          this.editor.storage.tableOfContents.content = headings;
          return true;
        },
    };
  },

  onCreate() {
    // 编辑器创建时，扫描初始文档
    const scanHeadings = (doc: any) => {
      const headings: Array<{
        id: string;
        textContent: string;
        level: number;
        originalLevel: number;
      }> = [];

      doc.descendants((node: any, pos: number) => {
        if (node.type.name === "heading") {
          const level = node.attrs.level as number;
          const textContent = node.textContent.trim();

          if (textContent) {
            const id = `heading-${pos}-${level}-${textContent
              .slice(0, 10)
              .replace(/\s/g, "")}`;

            headings.push({
              id,
              textContent,
              level,
              originalLevel: level,
            });
          }
        }
      });

      return headings;
    };

    // 确保 storage 存在
    if (!this.editor.storage.tableOfContents) {
      this.editor.storage.tableOfContents = {
        content: [],
      };
    }

    // 延迟执行，确保 storage 已初始化
    setTimeout(() => {
      const headings = scanHeadings(this.editor.state.doc);
      if (!this.editor.storage.tableOfContents) {
        this.editor.storage.tableOfContents = {
          content: [],
        };
      }
      this.editor.storage.tableOfContents.content = headings;
    }, 100);
  },

  addProseMirrorPlugins() {
    // 扫描文档中的标题节点的辅助函数
    const scanHeadings = (doc: any) => {
      const headings: Array<{
        id: string;
        textContent: string;
        level: number;
        originalLevel: number;
      }> = [];

      doc.descendants((node: any, pos: number) => {
        if (node.type.name === "heading") {
          const level = node.attrs.level as number;
          const textContent = node.textContent.trim();

          if (textContent) {
            // 生成唯一 ID（基于位置和内容）
            const id = `heading-${pos}-${level}-${textContent
              .slice(0, 10)
              .replace(/\s/g, "")}`;

            headings.push({
              id,
              textContent,
              level,
              originalLevel: level,
            });
          }
        }
      });

      return headings;
    };

    return [
      new Plugin({
        key: new PluginKey("tableOfContents"),
        state: {
          init: (_config, state) => {
            // 初始化时扫描文档
            scanHeadings(state.doc);
            return null;
          },
          apply: (_tr, _value, _oldState, newState) => {
            // 确保 storage 存在
            if (!this.editor.storage.tableOfContents) {
              this.editor.storage.tableOfContents = {
                content: [],
              };
            }

            // 每次事务都扫描文档（确保目录总是最新的）
            const headings = scanHeadings(newState.doc);

            // 更新 storage
            this.editor.storage.tableOfContents.content = headings;

            return null;
          },
        },
      }),
    ];
  },

  addStorage() {
    return {
      tableOfContents: {
        content: [] as Array<{
          id: string;
          textContent: string;
          level: number;
          originalLevel: number;
        }>,
      },
    };
  },
});
